﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace QLua.Generator;


[Generator]
public class LuaIncrementalGenerator : IIncrementalGenerator
{
	public void Initialize(IncrementalGeneratorInitializationContext context)
	{
		
		// 1. 查找所有被LuaExport标记的类
		IncrementalValuesProvider<ClassDeclarationSyntax> exportClasses = context.SyntaxProvider
			.CreateSyntaxProvider(
				predicate: (s, _) => IsSyntaxTargetForGeneration(s),
				transform: (ctx, _) => GetSemanticTargetForGeneration(ctx)
			)
			.Where(classDeclaration => classDeclaration is not null)!;

		// 2. 将语法节点与编译信息结合
		IncrementalValueProvider<(Compilation Compilation, ImmutableArray<ClassDeclarationSyntax> Classes)> compilationAndClasses =
			context.CompilationProvider.Combine(exportClasses.Collect());

		// 3. 生成代码
		context.RegisterSourceOutput(compilationAndClasses,
			(spc, source) => Execute(source.Compilation, source.Classes, spc));
	}
	private static bool IsSyntaxTargetForGeneration(SyntaxNode node)
	{
		return node is ClassDeclarationSyntax classDeclaration &&
			   classDeclaration.AttributeLists.Count > 0;
	}

	private static ClassDeclarationSyntax GetSemanticTargetForGeneration(GeneratorSyntaxContext context)
	{
		var classDeclaration = (ClassDeclarationSyntax)context.Node;

		// 检查是否有LuaExport属性
		foreach (var attributeList in classDeclaration.AttributeLists)
		{
			foreach (var attribute in attributeList.Attributes)
			{
				if (context.SemanticModel.GetSymbolInfo(attribute).Symbol is IMethodSymbol attributeSymbol &&
					attributeSymbol.ContainingType.ToDisplayString() == "QLua.LuaExportAttribute")
				{
					return classDeclaration;
				}
			}
		}

		return null;
	}

	private void Execute(Compilation compilation, ImmutableArray<ClassDeclarationSyntax> classes, SourceProductionContext context)
	{
		//if (!Debugger.IsAttached)
		//{
		//	Debugger.Launch();
		//}
		if (classes.IsDefaultOrEmpty)
			return;

		
		
		// 查找LuaExportAttribute和LuaMethodAttribute的类型信息
		var exportAttributeSymbol = compilation.GetTypeByMetadataName("QLua.LuaExportAttribute");
		var methodAttributeSymbol = compilation.GetTypeByMetadataName("QLua.LuaMethodAttribute");

		if (exportAttributeSymbol == null || methodAttributeSymbol == null)
			return;

		// 存储所有需要导出的类和方法信息
		var exportClasses = new List<ExportClassInfo>();

		foreach (var classDeclaration in classes)
		{
			// 获取类的语义信息
			if (compilation.GetSemanticModel(classDeclaration.SyntaxTree).GetDeclaredSymbol(classDeclaration) is not INamedTypeSymbol classSymbol)
				continue;

			var classInfo = new ExportClassInfo
			{
				Namespace = classSymbol.ContainingNamespace.ToString(),
				ClassName = classSymbol.Name,
				FullName = classSymbol.ToString()
			};

			// 查找类中的所有方法
			foreach (var method in classSymbol.GetMembers().OfType<IMethodSymbol>())
			{
				// 检查方法是否有LuaMethod属性
				var luaMethodAttr = method.GetAttributes().FirstOrDefault(attr =>
					attr.AttributeClass?.Equals(methodAttributeSymbol, SymbolEqualityComparer.Default) == true);

				if (luaMethodAttr != null)
				{
					var methodInfo = new ExportMethodInfo
					{
						MethodName = method.Name,
						ParameterTypes = method.Parameters.Select(p => p.Type.ToString()).ToList(),
						ReturnType = method.ReturnType.ToString()
					};

					// 获取可选的方法名称参数
					if (luaMethodAttr.ConstructorArguments.Length > 0 &&
						luaMethodAttr.ConstructorArguments[0].Value is string luaName &&
						!string.IsNullOrEmpty(luaName))
					{
						methodInfo.LuaName = luaName;
					}
					else
					{
						methodInfo.LuaName = method.Name;
					}

					classInfo.Methods.Add(methodInfo);
				}
			}

			if (classInfo.Methods.Count > 0)
			{
				exportClasses.Add(classInfo);
			}
		}

		// 生成注册代码
		if (exportClasses.Any())
		{
			var source = GenerateRegistrationCode(exportClasses);
			context.AddSource("LuaRegistration.g.cs", SourceText.From(source, Encoding.UTF8));
		}
	}

	private string GenerateRegistrationCode(List<ExportClassInfo> classes)
	{
	


		var sb = new StringBuilder();
		sb.AppendLine("// <auto-generated />");
		sb.AppendLine("using System;");
		
		sb.AppendLine("using QLua;");
		sb.AppendLine("namespace QLua.Common;");
		sb.AppendLine("    public static class LuaAutoRegistrar");
		sb.AppendLine("    {");
		sb.AppendLine("        public static void RegisterAll(Lua lua)");
		sb.AppendLine("        {");

		foreach (var classInfo in classes)
		{
			foreach (var method in classInfo.Methods)
			{
				// 生成方法注册代码
				sb.AppendLine($"		lua.RegisterFunction(\"{method.LuaName}\", null, typeof({classInfo.FullName}).GetMethod(\"{method.MethodName}\"));");
			}
		}

		sb.AppendLine("        }");
		sb.AppendLine("    }");
		

		return sb.ToString();
	}

	private class ExportClassInfo
	{
		public string Namespace { get; set; }
		public string ClassName { get; set; }
		public string FullName { get; set; }
		public List<ExportMethodInfo> Methods { get; } = new List<ExportMethodInfo>();
	}

	private class ExportMethodInfo
	{
		public string MethodName { get; set; }
		public string LuaName { get; set; }
		public string ReturnType { get; set; }
		public List<string> ParameterTypes { get; set; }
	}
}
